package com.sf.osms.dep.processor.util;

import java.io.IOException;
import java.io.Reader;

public class LineSplitBufferedReader extends Reader{

		private Reader in;

	    private char cb[];
	    private int nChars, nextChar;
	    private int charNum = 0;
	    private String lineSplit;
	    
	    private static final int INVALIDATED = -2;
	    private static final int UNMARKED = -1;
	    private int markedChar = UNMARKED;
	    private int readAheadLimit = 0; /* Valid only when markedChar > 0 */

	    /** If the next character is a line feed, skip it */
	    private boolean skipLF = false;

	    /** The skipLF flag when the mark was set */
	    private boolean markedSkipLF = false;

	    private static int defaultCharBufferSize = 8192;
	    private static int defaultExpectedLineLength = 80;

	    /**
	     * Creates a buffering character-input stream that uses an input buffer of
	     * the specified size.
	     *
	     * @param  in   A Reader
	     * @param  sz   Input-buffer size
	     *
	     * @exception  IllegalArgumentException  If {@code sz <= 0}
	     */
	    public LineSplitBufferedReader(Reader in, int sz) {
	        super(in);
	        if (sz <= 0)
	            throw new IllegalArgumentException("Buffer size <= 0");
	        this.in = in;
	        cb = new char[sz];
	        nextChar = nChars = 0;
	    }

	    /**
	     * Creates a buffering character-input stream that uses a default-sized
	     * input buffer.
	     *
	     * @param  in   A Reader
	     */
	    public LineSplitBufferedReader(Reader in) {
	        this(in, defaultCharBufferSize);
	        charNum = 0;
	    }

	    /** Checks to make sure that the stream has not been closed */
	    private void ensureOpen() throws IOException {
	        if (in == null)
	            throw new IOException("Stream closed");
	    }

	    /**
	     * Fills the input buffer, taking the mark into account if it is valid.
	     */
	    private void fill() throws IOException {
	        int dst;
	        if (markedChar <= UNMARKED) {
	            /* No mark */
	            dst = 0;
	        } else {
	            /* Marked */
	            int delta = nextChar - markedChar;
	            if (delta >= readAheadLimit) {
	                /* Gone past read-ahead limit: Invalidate mark */
	                markedChar = INVALIDATED;
	                readAheadLimit = 0;
	                dst = 0;
	            } else {
	                if (readAheadLimit <= cb.length) {
	                    /* Shuffle in the current buffer */
	                    System.arraycopy(cb, markedChar, cb, 0, delta);
	                    markedChar = 0;
	                    dst = delta;
	                } else {
	                    /* Reallocate buffer to accommodate read-ahead limit */
	                    char ncb[] = new char[readAheadLimit];
	                    System.arraycopy(cb, markedChar, ncb, 0, delta);
	                    cb = ncb;
	                    markedChar = 0;
	                    dst = delta;
	                }
	                nextChar = nChars = delta;
	            }
	        }

	        int n;
	        do {
	            n = in.read(cb, dst, cb.length - dst);
	        } while (n == 0);
	        if (n > 0) {
	            nChars = dst + n;
	            nextChar = dst;
	        }
	    }

	    /**
	     * Reads a single character.
	     *
	     * @return The character read, as an integer in the range
	     *         0 to 65535 (<tt>0x00-0xffff</tt>), or -1 if the
	     *         end of the stream has been reached
	     * @exception  IOException  If an I/O error occurs
	     */
	    public int read() throws IOException {
	        synchronized (lock) {
	            ensureOpen();
	            for (;;) {
	                if (nextChar >= nChars) {
	                    fill();
	                    if (nextChar >= nChars)
	                        return -1;
	                }
	                if (skipLF) {
	                    skipLF = false;
	                    if (cb[nextChar] == '\n') {
	                        nextChar++;
	                        continue;
	                    }
	                }
	                return cb[nextChar++];
	            }
	        }
	    }

	    /**
	     * Reads characters into a portion of an array, reading from the underlying
	     * stream if necessary.
	     */
	    private int read1(char[] cbuf, int off, int len) throws IOException {
	        if (nextChar >= nChars) {
	            /* If the requested length is at least as large as the buffer, and
	               if there is no mark/reset activity, and if line feeds are not
	               being skipped, do not bother to copy the characters into the
	               local buffer.  In this way buffered streams will cascade
	               harmlessly. */
	            if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
	                return in.read(cbuf, off, len);
	            }
	            fill();
	        }
	        if (nextChar >= nChars) return -1;
	        if (skipLF) {
	            skipLF = false;
	            if (cb[nextChar] == '\n') {
	                nextChar++;
	                if (nextChar >= nChars)
	                    fill();
	                if (nextChar >= nChars)
	                    return -1;
	            }
	        }
	        int n = Math.min(len, nChars - nextChar);
	        System.arraycopy(cb, nextChar, cbuf, off, n);
	        nextChar += n;
	        return n;
	    }

	   
	    public int read(char cbuf[], int off, int len) throws IOException {
	        synchronized (lock) {
	            ensureOpen();
	            if ((off < 0) || (off > cbuf.length) || (len < 0) ||
	                ((off + len) > cbuf.length) || ((off + len) < 0)) {
	                throw new IndexOutOfBoundsException();
	            } else if (len == 0) {
	                return 0;
	            }

	            int n = read1(cbuf, off, len);
	            if (n <= 0) return n;
	            while ((n < len) && in.ready()) {
	                int n1 = read1(cbuf, off + n, len - n);
	                if (n1 <= 0) break;
	                n += n1;
	            }
	            return n;
	        }
	    }

	   
	    String readLine(boolean ignoreLF) throws IOException {
	        StringBuffer s = null;
	        int startChar;

	        synchronized (lock) {
	            ensureOpen();
	            boolean omitLF = ignoreLF || skipLF;

	        bufferLoop:
	            for (;;) {

	                if (nextChar >= nChars)
	                    fill();
	                if (nextChar >= nChars) { /* EOF */
	                    if (s != null && s.length() > 0)
	                        return s.toString();
	                    else
	                        return null;
	                }
	                boolean eol = false;
	                char c = 0;
	                int i;

	                /* Skip a leftover '\n', if necessary */
	                if (omitLF && (cb[nextChar] == '\n'))
	                    nextChar++;
	                skipLF = false;
	                omitLF = false;

	            charLoop:
	                for (i = nextChar; i < nChars; i++) {
	                    c = cb[i];
	                    if (c == lineSplit.charAt(0)) {
	                        eol = true;
	                        break charLoop;
	                    }
	                }

	                startChar = nextChar;
	                nextChar = i;

	                if (eol) {
	                    String str;
	                    if (s == null) {
	                        str = new String(cb, startChar, i - startChar);
	                    } else {
	                        s.append(cb, startChar, i - startChar);
	                        str = s.toString();
	                    }
	                    nextChar++;
	                    if (c == '\r') {
	                        skipLF = true;
	                    }
	                    return str;
	                }

	                if (s == null)
	                    s = new StringBuffer(defaultExpectedLineLength);
	                s.append(cb, startChar, i - startChar);
	            }
	        }
	    }
	    
	    String readLineCharNum(boolean ignoreLF) throws IOException {
	        StringBuffer s = null;
	        int startChar;

	        synchronized (lock) {
	            ensureOpen();
	            boolean omitLF = ignoreLF || skipLF;

	        bufferLoop:
	            for (;;) {

	                if (nextChar >= nChars)
	                    fill();
	                if (nextChar >= nChars) { /* EOF */
	                    if (s != null && s.length() > 0)
	                        return s.toString();
	                    else
	                        return null;
	                }
	                boolean eol = false;
	                char c = 0;
	                int i;

	                /* Skip a leftover '\n', if necessary */
	                if (omitLF && (cb[nextChar] == '\n'))
	                    nextChar++;
	                skipLF = false;
	                omitLF = false;

	            charLoop:
	                for (i = nextChar; i < nChars; i++) {
	                    c = cb[i];
	                    if ((i+1) % Integer.valueOf(lineSplit) == 0) {
	                        eol = true;
	                        break charLoop;
	                    }
	                }

	                startChar = nextChar;
	                nextChar = i;

	                if (eol) {
	                    String str;
	                    if (s == null) {
	                        str = new String(cb, startChar, i - startChar+1);
	                    } else {
	                        s.append(cb, startChar, i - startChar+1);
	                        str = s.toString();
	                    }
	                    nextChar++;
	                    if (c == '\r') {
	                        skipLF = true;
	                    }
	                    return str;
	                }

	                if (s == null)
	                    s = new StringBuffer(defaultExpectedLineLength);
	                s.append(cb, startChar, i - startChar);
	            }
	        }
	    }
	    
	  
	    public String readLine() throws IOException {
	    	try {
	    		Integer.valueOf(lineSplit);
	    		return readLineCharNum(false);
			} catch (Exception e) {
				 return readLine(false);
			}
	    	
	       
	    }

	  
	    public long skip(long n) throws IOException {
	        if (n < 0L) {
	            throw new IllegalArgumentException("skip value is negative");
	        }
	        synchronized (lock) {
	            ensureOpen();
	            long r = n;
	            while (r > 0) {
	                if (nextChar >= nChars)
	                    fill();
	                if (nextChar >= nChars) /* EOF */
	                    break;
	                if (skipLF) {
	                    skipLF = false;
	                    if (cb[nextChar] == '\n') {
	                        nextChar++;
	                    }
	                }
	                long d = nChars - nextChar;
	                if (r <= d) {
	                    nextChar += r;
	                    r = 0;
	                    break;
	                }
	                else {
	                    r -= d;
	                    nextChar = nChars;
	                }
	            }
	            return n - r;
	        }
	    }

	    /**
	     * Tells whether this stream is ready to be read.  A buffered character
	     * stream is ready if the buffer is not empty, or if the underlying
	     * character stream is ready.
	     *
	     * @exception  IOException  If an I/O error occurs
	     */
	    public boolean ready() throws IOException {
	        synchronized (lock) {
	            ensureOpen();

	            /*
	             * If newline needs to be skipped and the next char to be read
	             * is a newline character, then just skip it right away.
	             */
	            if (skipLF) {
	                /* Note that in.ready() will return true if and only if the next
	                 * read on the stream will not block.
	                 */
	                if (nextChar >= nChars && in.ready()) {
	                    fill();
	                }
	                if (nextChar < nChars) {
	                    if (cb[nextChar] == '\n')
	                        nextChar++;
	                    skipLF = false;
	                }
	            }
	            return (nextChar < nChars) || in.ready();
	        }
	    }

	    /**
	     * Tells whether this stream supports the mark() operation, which it does.
	     */
	    public boolean markSupported() {
	        return true;
	    }

	 
	    public void mark(int readAheadLimit) throws IOException {
	        if (readAheadLimit < 0) {
	            throw new IllegalArgumentException("Read-ahead limit < 0");
	        }
	        synchronized (lock) {
	            ensureOpen();
	            this.readAheadLimit = readAheadLimit;
	            markedChar = nextChar;
	            markedSkipLF = skipLF;
	        }
	    }

	 
	    public void reset() throws IOException {
	        synchronized (lock) {
	            ensureOpen();
	            if (markedChar < 0)
	                throw new IOException((markedChar == INVALIDATED)
	                                      ? "Mark invalid"
	                                      : "Stream not marked");
	            nextChar = markedChar;
	            skipLF = markedSkipLF;
	        }
	    }

	    public void close() throws IOException {
	        synchronized (lock) {
	            if (in == null)
	                return;
	            try {
	                in.close();
	            } finally {
	                in = null;
	                cb = null;
	            }
	        }
	    }

		public String getLineSplit() {
			return lineSplit;
		}

		public void setLineSplit(String lineSplit) {
			this.lineSplit = lineSplit;
		}
}
